home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / networke / civ-0.000 / civ-0 / civ-0.3 / src / player.cc < prev    next >
C/C++ Source or Header  |  1996-03-04  |  29KB  |  1,070 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #ifndef MS_WIN
  4. #include <unistd.h>
  5.  
  6. #else
  7.  
  8. int sleep(int n)
  9. {
  10.   return 0;
  11. }
  12.  
  13. #endif
  14.  
  15. #include "defs.h"
  16. #include "world.h"
  17. #include "player.h"
  18. #include "trans.h"
  19. #include "move.h"
  20. #include "units.h"
  21. #include "graph.h"
  22. #include "keyboard.h"
  23. #include "MsgQ.h"
  24. #include "city.h"
  25. #include "display.h"
  26. #include "misc.h"
  27. #include "rules.h"
  28. #include "savefile.h"
  29.  
  30. void NetFail(char *str)
  31. {
  32.   printf("Network failure %s\n", str);
  33.   exit(1);
  34. }
  35.  
  36. static void FixX(int &x)
  37. {
  38.   x = (x-HorizSpace)/SquareWidth;
  39.   if (x < 0) x = 0;
  40.   if (x >= SquaresWide) x = SquaresWide-1;
  41. }
  42.  
  43. static void FixY(int &y)
  44. {
  45.   y = (y-VertSpace)/SquareHeight;
  46.   if (y < 0) y = 0;
  47.   if (y >= SquaresHigh) y = SquaresHigh-1;
  48. }
  49.  
  50. static void ShowPoint(int x, int y)
  51. {
  52.   int wx, wy;
  53.   if (x >= HorizSpace || y < VertSpace || y >= VertSpace+64) {
  54.     FixX(x);
  55.     FixY(y);
  56.     display->TranslateWorld(x, y, wx, wy);
  57.   }
  58.   else {
  59.     y -= VertSpace;
  60.     wx = (x*world->MaxX())/HorizSpace;
  61.     wy = (y*world->MaxY())/64;
  62.   }
  63.   display->Center(wx, wy);
  64. }
  65.  
  66. // colors for players
  67. static char *color_tbl[] = {
  68.   "#e8e8e8e8e8e8", "#0c0ce0e0e8e8",
  69.   "#ad00ff002f00", "#e8e8e8e8e8e8",
  70.   "NavyBlue", "#e8e8e8e8e8e8",
  71.   "DarkGray", "#e8e8e0e0e8e8" };
  72.  
  73. Player::Player(char *Name, int Id)
  74. {
  75.   name = Name;
  76.   sprintf(color1Str, "x c %s", color_tbl[Id*2]);
  77.   sprintf(color2Str, "x c %s", color_tbl[Id*2+1]);
  78.   id = Id;
  79.   cityPic = 0;
  80.   doneMoving = 0;
  81.   govt = DESPOT;
  82.   tax = 50;
  83.   luxuries = 0;
  84.   money = 0;
  85.   initiatedSave = 0;
  86.  
  87.   templeEffect = 1;
  88.   cathedralEffect = 4;
  89.   seamoveBonus = 0;
  90.   tradeBonus = 0;
  91.  
  92.   if (!savedGame)
  93.     InitialScience(id, discovered, canDiscover, canBuild, canGovern);
  94.   researching = NULL;
  95.  
  96.   scienceAcc = 0;
  97.   needScience = 10;
  98.  
  99.   state = NORMAL;
  100. }
  101.  
  102. Player::~Player()
  103. {
  104.   delete name;
  105. }
  106.  
  107. int Player::HasWonder(char *name)
  108. {
  109.   for (Lister<charp> l = wonders; l; l.Next())
  110.     if (strcmp(l.Elem(), name) == 0) return 1;
  111.   return 0;
  112. }
  113.  
  114. void Player::DeleteWonder(char *name)
  115. {
  116.   for (Lister<charp> l = wonders; l; l.Next())
  117.     if (strcmp(l.Elem(), name) == 0) {
  118.       l.Delete();
  119.       return;
  120.     }
  121. }
  122.  
  123. long Player::CompilePic(char **pic)
  124. {
  125.   char *ptr1 = pic[1], *ptr2 = pic[2];
  126.   color1Str[0] = ptr1[0];
  127.   color2Str[0] = ptr2[0];
  128.   pic[1] = color1Str;
  129.   pic[2] = color2Str;
  130.   long handle = screen->CompilePixmap(pic);
  131.   pic[1] = ptr1;
  132.   pic[2] = ptr2;
  133.   return handle;
  134. }
  135.  
  136. // create the first settler for the player
  137. void Player::Setup()
  138. {
  139.   // find a nice random place on the map which has at least a
  140.   // 5x5 block of land around it
  141.   Debug('i', "Trying to setup\n");
  142.   int x, y;
  143.   while (1) {
  144.     while (1) {
  145.       x = random() % world->MaxX();
  146.       y = random() % world->MaxY();
  147.       int goodspot = 1;
  148.       for (int x1 = -2; x1 <= 2; ++x1) for (int y1 = -2; y1 <= 2; ++y1)
  149.         if (world->Terrain((x+x1+world->MaxX())%world->MaxX(),
  150.              (y+y1+world->MaxY())%world->MaxY()) == WATER)
  151.     { goodspot = 0; break; }
  152.       if (goodspot) break;
  153.     }
  154.     if (!world->NextToOpponent(id,x,y)) break;
  155.   }
  156.   // Unit constructor automatically adds it to the world and to the
  157.   // list of units for the player
  158.   Debug('i', "found spot %d %d\n", x, y);
  159.   Unit *settler = NewUnit(SETTLER, id, trans->New(), 0, 0, x, y);
  160.   moveQ = new MsgQ;
  161.   *moveQ << PieceMove(settler->id, PIECE_CREATE, x, y, SETTLER,
  162.               0, 0);
  163. }
  164.  
  165. // send all the moves across
  166. void Player::SendMoves(MsgQ *q)
  167. {
  168.   *q << "moves";
  169.  
  170.   Debug('p', "sending moves\n");
  171.   *q << *moveQ;
  172.   delete moveQ;
  173.   moveQ = NULL;
  174. }
  175.  
  176. // show the moves made
  177. void Player::ShowMoves(MsgQ *q, MsgQ *outQ)
  178. {
  179.   City *city;
  180.   Unit *unit;
  181.   char *name;
  182.   int fortStat;
  183.   while (q->Count() > 0) {
  184.     Msg m;
  185.     *q >> m;
  186.     PieceMove *move = (PieceMove*)m.buf;
  187.     move->HostOrder();
  188.     switch (move->oper) {
  189.     case PIECE_CREATE:
  190.       unit = NewUnit(move->type, id, move->id, move->veteran,
  191.              move->city, move->x, move->y);
  192.       Debug('u', "Created new unit type %d, id %ld, at %d %d\n", move->type,
  193.         unit->id, move->x, move->y);
  194.       break;
  195.     case PIECE_MOVE:
  196.       // moving into a city automatically captures it
  197.       // if a city is captured and it is the city for the player whose
  198.       // civ this is, MoveUnit will tell the city to send its info across
  199.       // it must tell the server to send the message to the owner of the
  200.       // piece only
  201.       MoveUnit(trans->TransUnit(move->id), move->x, move->y, 0.0, outQ);
  202.       sleep(1);
  203.       break;
  204.     case PIECE_DIE:
  205.       delete trans->TransUnit(move->id);
  206.       break;
  207.     case CITY_CREATE:
  208.       *q >> name;
  209.       city = new City(name, move->id, move->x, move->y, id);
  210.       break;
  211.     case CITY_DIE:
  212.       delete trans->TransCity(move->id);
  213.       break;
  214.     case CITY_SIZE:
  215.       city = trans->TransCity(move->id);
  216.       city->size = move->x;
  217.       city->DrawIfVisible();
  218.       break;
  219.     case CITY_WALL:
  220.       city = trans->TransCity(move->id);
  221.       if (move->x) {
  222.         if (!city->HasBuilding("City Walls"))
  223.           city->buildings.Insert("City Walls");
  224.       } else {
  225.         for (Lister<charp> l = city->buildings; l; l.Next())
  226.           if (strcmp(l.Elem(),"City Walls")==0) {
  227.             l.Delete();
  228.             continue;
  229.           }
  230.       }
  231.       city->DrawIfVisible();
  232.       break;
  233.     case CITY_WORK_MAP:
  234.       city = trans->TransCity(move->id);
  235.       city->TransWorkMap(q);
  236.       break;
  237.     case UNIT_UPDATE:
  238.       unit = trans->TransUnit(move->id);
  239.       fortStat = unit->Fortified();
  240.       if (move->x)
  241.     unit->Fortify();
  242.       else
  243.     unit->UnFortify();
  244.       if (move->y) unit->MakeVeteran();
  245.       if (fortStat != unit->Fortified())
  246.     unit->DrawIfVisible();
  247.       break;
  248.     case DISCOVERY: // some player has discovered something
  249.       {
  250.     *q >> name;
  251.     Player *p = players[move->id];
  252.     Discover(move->id, name, p->discovered, p->canDiscover,
  253.          p->canBuild, p->canGovern);
  254.     delete name;
  255.     break;
  256.       }
  257.     case WONDER: // someone else has built a wonder
  258.       {
  259.     *q >> name;
  260.     Player *p = players[move->id];
  261.     BuildObject *obj = buildObjects.Find(StrKey(name));
  262.     obj->built = 1;
  263.     p->wonders.Insert(obj->name);
  264.     AddMessage(players[playerId]->messages, "%s builds %s\n",
  265.            p->name, obj->name);
  266.     delete name;
  267.       }
  268.     case TERRAIN_CHANGE:
  269.       world->Set(move->x, move->y, move->type);
  270.       if (world->Visible(move->x, move->y) &&
  271.       display->Visible(move->x, move->y)) {
  272.     int sx, sy;
  273.     display->TranslateScreen(move->x, move->y, sx, sy);
  274.     world->Draw(move->x, move->y, 1, 1, sx, sy);
  275.       }
  276.       break;
  277.     }
  278.     delete move;
  279.   }
  280. }
  281.  
  282. void Player::InitMoveTurn()
  283. {
  284.   Debug('p', "initmoveturn for %d\n", id);
  285.   if (initiatedSave) {
  286.     MsgQ *q = new MsgQ;
  287.     *q << "save_game";
  288.     SendQ(q);
  289.     CreateSaveFile();
  290.     acks_left = numPlayers-1;
  291.     accepts_left = 0;
  292.     screen->DisplayMessage("Waiting for save", 0);
  293.   }
  294.   else {
  295.     MsgQ *q = new MsgQ;
  296.     *q << "myturn";
  297.     *q << id;
  298.     SendQ(q);
  299.     moveQ = new MsgQ;
  300.     acks_left = numPlayers-1;
  301.     accepts_left = 0;
  302.     screen->DisplayMessage("Your Turn", 0);
  303.     doneMoving = 0;
  304.   }
  305. }
  306.  
  307. void Player::MoveTurnMesg(MsgQ *q)
  308. {
  309.   char *mesg;
  310.   *q >> mesg;
  311.   if (initiatedSave && playerId == 0 && strcmp(mesg, "done_save") == 0) {
  312.     if (--acks_left <= 0)
  313.       exit(0);
  314.   }
  315.   if (strcmp(mesg, "yourturn_ack") == 0) {
  316.     if (--acks_left <= 0) {
  317.       // startup moveturn
  318.  
  319.       if (researching == NULL) {
  320.     state = IN_SELECT;
  321.     selecting = SCIENCE;
  322.     screen->CreateChoiceFrame("Choose Research", canDiscover);
  323.       }
  324.  
  325.       UpdateCities();
  326.       display->ShowPlayerInfo();
  327.  
  328.       currUnit = NULL;
  329.       Lister<ulong> unitl = units;
  330.       while (unitl) {
  331.     Unit *ptr = trans->TransUnit(unitl.Elem());
  332.     ptr->numMoves = ptr->Moves(players[playerId]->seamoveBonus);
  333.     ptr->CompleteOrder();
  334.     if (currUnit == NULL && ptr->numMoves > 0) currUnit = ptr;
  335.     unitl.Next();
  336.       }
  337.       if (currUnit == NULL)
  338.     screen->DisplayMessage("End of Turn, press Enter", 0);
  339.       else if (state != IN_SELECT) {
  340.     display->ShowPiece(currUnit->x, currUnit->y, currUnit->id);
  341.     display->EnableCursor(currUnit->x, currUnit->y, currUnit->id);
  342.       }
  343.     }
  344.   }
  345.   else if (strcmp(mesg, "got_moves") == 0) {
  346.     // if we took over any cities of this guy there will be more messages
  347.     if (q->Count() > 0)
  348.       GetCapturedCity(q, this);
  349.     if (--acks_left <= 0) {
  350.       currTurn = (currTurn+1) % numPlayers;
  351.       doneMoving = 0;
  352.       InitCityTurn();
  353.     }
  354.   }
  355.   else if (strcmp(mesg, "city_info") == 0) {
  356.     // get captured city info here
  357.   }
  358.   delete mesg;
  359.   delete q;
  360.   return;
  361. }
  362.  
  363. void Player::SelectEvent(int event, int x, int y, char *data)
  364. {
  365.   if (state != IN_SELECT) return;
  366.   if (event != SELECT) return;
  367.   if (selecting == SCIENCE) { // selecting science
  368.     Debug('p', "Selected science %s\n", data);
  369.     Science *ptr = sciences.Find(StrKey(data));
  370.     researching = ptr->name;
  371.     needScience = DiscoverCost(id,ptr);    
  372.     display->ShowPlayerInfo();
  373.     state = NORMAL;
  374.   }
  375.   // MarkM added government type:
  376.   else if (selecting == GOVERNMENT_TYPE) {
  377.     if (strcmp(data,"Despotism") == 0) govt = DESPOT;
  378.     else if (strcmp(data,"Monarchy") == 0) govt = MONARCH;
  379.     else if (strcmp(data,"The Republic") == 0) govt = REPUBLIC;
  380.     else if (strcmp(data,"Democracy") == 0) govt = DEMOCRACY;
  381.     state = NORMAL;
  382.   }
  383.   else if (selecting == TAX_RATE) {
  384.     sscanf(data, "Tax %d\n", &tax);
  385.     for (Lister<ulong> l = citys; l; l.Next())
  386.     trans->TransCity(l.Elem())->ComputeEcon();
  387.     display->ShowPlayerInfo();
  388.     state = NORMAL;
  389.   } 
  390.   // MarkM added luxuries rate:
  391.   else if (selecting == LUXURY_RATE) {
  392.     sscanf(data, "Luxuries %d\n", &luxuries);
  393.     for (Lister<ulong> l = citys; l; l.Next())
  394.         trans->TransCity(l.Elem())->ComputeEcon();
  395.     display->ShowPlayerInfo();
  396.     state = NORMAL;
  397.   }
  398.   // MarkM added revolution choice:
  399.   else if (selecting == REVOLUTION) {
  400.     if (strncmp(data,"Yes",3) == 0) govt = ANARCHY;
  401.     state = NORMAL;
  402.   }
  403.   // MarkM added buying current build-project:
  404.   else if (selecting == BUILD_BUY) {
  405.     if (strncmp(data,"Yes",3) == 0) {
  406.       City *city = display->CurrCity();
  407.       int cost = (int) ((city->needProd - city->accProd) * 2.5);
  408.       if (money >= cost) {
  409.         money -= cost;
  410.         city->accProd = city->needProd;
  411.         city->ShowWorkInProg();
  412.       }
  413.     }
  414.     state = NORMAL;
  415.   } else if (selecting == CITY_BUILDING) {
  416.     // have to isolate the object
  417.     char *endp = strchr(data, '/');
  418.     if (endp)
  419.       *endp = '\0';
  420.     endp = strrchr(data, ' ');
  421.     *endp = '\0';
  422.     Debug('p', "Selected building %s\n", data);
  423.     City *city = display->CurrCity();
  424.     BuildObject *obj = buildObjects.Find(StrKey(data));
  425.     if (obj != NULL) Debug('p', "Found obj %s\n", obj->name);
  426.     city->WorkOn(obj->name);
  427.     state = NORMAL;
  428.     city->ShowWorkInProg();
  429.   }
  430.   return;
  431. }
  432.  
  433. void Player::MoveTurnKey(int event, int x, int y, char *data)
  434. {
  435.   int showPiece = 1;
  436.   display->DisableCursor();
  437.   if (state == IN_SELECT) {
  438.     SelectEvent(event, x, y, data);
  439.   }
  440.   else if (event == MOUSE_RIGHT) { // right button, center the square
  441.     ShowPoint(x, y);
  442.     showPiece = 0; // if invisible don't show
  443.   }
  444.   else if (event == MOUSE_LEFT && !doneMoving) {
  445.     // check for fortified or sleeping pieces and wake them up
  446.     FixX(x); FixY(y);
  447.     int wx, wy;
  448.     Unit *found = NULL;
  449.     display->TranslateWorld(x, y, wx, wy);
  450.     for (Lister<ulong> l = world->Units(wx, wy); l; l.Next()) {
  451.       Unit *ptr = trans->TransUnit(l.Elem());
  452.       if (ptr->currOrder == 's') {
  453.     ptr->currOrder = ' ';
  454.     ptr->numMoves = ptr->Moves(players[playerId]->seamoveBonus);
  455.     found = ptr;
  456.       }
  457.       else if (ptr->currOrder == 'f') {
  458.     ptr->currOrder = ' ';
  459.     ptr->UnFortify();
  460.     ptr->numMoves = ptr->Moves(players[playerId]->seamoveBonus);
  461.     found = ptr;
  462.     // tell other players
  463.     *moveQ << PieceMove(ptr->id, UNIT_UPDATE, 0,
  464.                 ptr->Veteran() != 0 ? 1 : 0);
  465.       }
  466.     }
  467.     if ((currUnit == NULL || currUnit->numMoves <= 0) && found != NULL)
  468.       currUnit = found;
  469.   }
  470.   else if (event == KEYBOARD && !doneMoving) {
  471.     int key = x;
  472.     Lister<ulong> unitl = units;
  473.     if (currUnit != NULL) {
  474.       if (MovementKey(key)) {
  475.         int tmpy = currUnit->y+MoveYDir(key);
  476.     int newx = (currUnit->x+MoveXDir(key)+world->MaxX()) % world->MaxX();
  477.     int newy = (tmpy+world->MaxY()) % world->MaxY();
  478. #ifdef NEWWORLD
  479.         if (newy == tmpy) {
  480. #endif
  481.         int terrain = world->Terrain(newx, newy);
  482.         if (currUnit->CanMoveOn(terrain, newx, newy)
  483.             && !world->OpponentPresent(playerId,newx,newy)) {
  484.         // only diplomat and caravan can move in opponent zone of control
  485.           if ((currUnit->type==DIPLOMAT) || (currUnit->type==CARAVAN)
  486.                || !(world->NextToOpponent(playerId,currUnit->x,currUnit->y)
  487.                && world->NextToOpponent(playerId,newx,newy)) )
  488.           {
  489.             double cost = currUnit->MoveCost(terrain, currUnit->numMoves,
  490.                                              currUnit->x, currUnit->y,
  491.                                              newx, newy);
  492.             if (cost < 0)
  493.               currUnit->numMoves = 0;
  494.             else {
  495.               if (!MoveUnit(currUnit, newx, newy, cost, NULL))
  496.                currUnit = NULL;
  497.               sleep(1);
  498.             }
  499.           }
  500. #ifdef NEWWORLD
  501.         }
  502. #endif
  503.     }
  504.         else { 
  505.       // see if the unit can attack an enemy unit
  506.       Lister<ulong> unitsl = world->Units(newx, newy);
  507.       int canAttack = 0;
  508.       while (unitsl && !canAttack) {
  509.         Unit *ptr = trans->TransUnit(unitsl.Elem());
  510.         if (ptr->ownerId != playerId && currUnit->CanAttack(ptr->Type()))
  511.           canAttack = 1;
  512.         unitsl.Next();
  513.       }
  514.       if (canAttack) {
  515.         if (!MoveUnit(currUnit, newx, newy, 1.0, NULL))
  516.           currUnit = NULL;
  517.         sleep(1);
  518.       }
  519.         }
  520.         if (currUnit != NULL && currUnit->numMoves <= 0)
  521.           key = 'n';
  522.       }
  523.       if (key == 'n' && currUnit != NULL) { // select next unit
  524.     Lister<ulong> unitl = units;
  525.     while (unitl && unitl.Elem() != currUnit->id) unitl.Next();
  526.     if (unitl) unitl.Next();
  527.     currUnit = NULL;
  528.     while (unitl &&
  529.            (currUnit = trans->TransUnit(unitl.Elem()))->numMoves <= 0)
  530.       unitl.Next();
  531.       }
  532.       if (currUnit != NULL && !currUnit->Order(key)) {
  533.     Debug('p', "Killing unit %d\n", currUnit->id);
  534.     delete currUnit;
  535.     currUnit = NULL;
  536.       }
  537.     }
  538.     if (currUnit == NULL || currUnit->numMoves <= 0) {
  539.       unitl = units;
  540.       while (unitl &&
  541.          (currUnit = trans->TransUnit(unitl.Elem()))->numMoves <= 0)
  542.     unitl.Next();
  543.     }
  544.     if (currUnit == NULL || currUnit->numMoves <= 0) {
  545.       // move turn is done
  546.       currUnit = NULL;
  547.       screen->DisplayMessage("Waiting for Acknowledgement", 0);
  548.       MsgQ *q = new MsgQ;
  549.       *q << "turn_done";
  550.       *q << id;
  551.       SendMoves(q);
  552.       SendQ(q);
  553.       acks_left = numPlayers-1;
  554.       accepts_left = 0;
  555.       doneMoving = 1;
  556.     }
  557.   }
  558.   if (!doneMoving && state != IN_SELECT && currUnit != NULL && currUnit->numMoves > 0) {
  559.     if (showPiece)
  560.       display->ShowPiece(currUnit->x, currUnit->y, currUnit->id);
  561.     if (display->Visible(currUnit->x, currUnit->y))
  562.       display->EnableCursor(currUnit->x, currUnit->y, currUnit->id);
  563.   }
  564. }
  565.  
  566. City *Player::FindCityWithMsg()
  567. {
  568.   for (Lister<ulong> l = citys; l; l.Next()) {
  569.     City *city = trans->TransCity(l.Elem());
  570.     if (city->messages) return city;
  571.   }
  572.   return NULL;
  573. }
  574.  
  575. void Player::InitCityTurn()
  576. {
  577.   Debug('p', "InitCityTurn for %d\n", id);
  578.   screen->DisplayMessage(players[currTurn]->name, 0);
  579.   City *city;
  580.   if ((city = FindCityWithMsg()) != NULL) {
  581.     display->ShowCityInfo(city);
  582.     screen->MessageBox(city->messages.RemoveHead());
  583.   }
  584.   else if (messages)
  585.     screen->MessageBox(messages.RemoveHead());
  586. }
  587.  
  588. // MarkM added government-type choice:
  589. void Player::ChooseGovernment()
  590. {
  591.     state = IN_SELECT;
  592.     selecting = GOVERNMENT_TYPE;
  593.     screen->CreateChoiceFrame("Choose Government", canGovern);
  594. }
  595.  
  596. // called when a key is pressed in the city turn
  597. void Player::CityTurnKey(int event, int x, int y, char *data)
  598. {
  599.   if (state == IN_SELECT) {
  600.     SelectEvent(event, x, y, data);
  601.     return;
  602.   }
  603.   if (event == MESG_READ) {
  604.     if (messages)
  605.       screen->MessageBox(messages.RemoveHead());
  606.     else {
  607.       City *city = display->CurrCity();
  608.       if (city->messages)
  609.     screen->MessageBox(city->messages.RemoveHead());
  610.     }
  611.     return;
  612.   }
  613.   if (event == MOUSE_LEFT && display->InMap()) {
  614.     FixX(x); FixY(y);
  615.     int wx, wy;
  616.     display->TranslateWorld(x, y, wx, wy);
  617.     if (world->WhichCity(wx, wy) != 0) {
  618.       City *city = trans->TransCity(world->WhichCity(wx, wy));
  619.       if (city->ownerId != id) return;
  620.       display->ShowCityInfo(city);
  621.     }
  622.     return;
  623.   }
  624.   if (event == MOUSE_LEFT && display->InCity()) {
  625.     x = (x-120)/SquareWidth;
  626.     y = (y-24)/SquareHeight;
  627.     if (x < 0 || x > 4 || y < 0 || y > 4) return;
  628.     x -= 2;
  629.     y -= 2;
  630.     Debug('c', "Clicked on square %d %d\n", x, y);
  631.     if (x == 0 && y == 0) return;
  632.     City *city = display->CurrCity();
  633.     int wx = (city->x+x+world->MaxX())%world->MaxX();
  634.     int wy = (city->y+y+world->MaxY())%world->MaxY();
  635.     if (world->RealVisible(wx, wy) == 0) return;
  636.     if (world->Working(wx, wy) == city->id) { // take off
  637.       world->Working(wx, wy) = 0;
  638.       city->ComputeEcon();
  639.       city->DrawCityMap();
  640.       city->ShowPeople();
  641.       city->ShowEcon();
  642.     }
  643.     else if (world->Working(wx, wy) == 0) {
  644.       city->ComputeEcon();
  645.       if (city->elvi <= 0) return;
  646.       world->Working(wx,  wy) = city->id;
  647.       city->ComputeEcon();
  648.       city->DrawCityMap();
  649.       city->ShowPeople();
  650.       city->ShowEcon();
  651.     }
  652.     return;
  653.   }
  654.   if (event == MOUSE_RIGHT && display->InMap()) {
  655.     ShowPoint(x, y);
  656.     return;
  657.   }
  658.   if (event != KEYBOARD) return;
  659.   int ch = x;
  660.   if (ch == 'a' && players[currTurn]->doneMoving) {
  661.     // accepted his moves, show them, if he captured our city
  662.     // we will send the info for it across too
  663.     display->ShowMap();
  664.     Debug('p', "showing players moves\n");
  665.     players[currTurn]->doneMoving = 0;
  666.     MsgQ *q = new MsgQ;
  667.     *q << "got_moves";
  668.     players[currTurn]->ShowMoves(players[currTurn]->unDispQ, q);
  669.     SendQ(q);
  670.     // next player's turn
  671.     currTurn = (currTurn+1) % numPlayers;
  672.     Debug('p', "currTurn %d, my id %d\n", currTurn, id);
  673.     if (currTurn == id) {
  674.       InitMoveTurn();
  675.     } else {
  676.       screen->DisplayMessage(players[currTurn]->name, 0);
  677.     }
  678.   }
  679.   else if (ch == 'c' && display->InCity()) { // change working on
  680.     City *city = display->CurrCity();
  681.     List<charp> build = city->CanBuild();
  682.     state = IN_SELECT;
  683.     selecting = CITY_BUILDING;
  684.     screen->CreateChoiceFrame("Select ...", build);
  685.     build.Delete();
  686.   }
  687.   else if (ch == 'b' && display->InCity()) { // buy what we're working on
  688.     City *city = display->CurrCity();
  689.     int cost = (int) ((city->needProd - city->accProd)*2.5);
  690.     if (cost > 0 && cost < money) {
  691.       List<charp> buyl;
  692.       char *str = new char[30];
  693.       sprintf(str,"Buy %s ?", city->building);
  694.       char *str1 = new char[50];
  695.       sprintf(str1,"Yes, buy %s for %d coin",city->building,cost);
  696.       buyl.Insert(str1);
  697.       char *str2 = new char[50];
  698.       sprintf(str2,"No, do not buy %s",city->building);
  699.       buyl.Insert(str2);
  700.       state = IN_SELECT;
  701.       selecting = BUILD_BUY;
  702.       screen->CreateChoiceFrame(str, buyl);
  703.       buyl.Delete();
  704.     }
  705.   }
  706.   else if (ch == 't' && display->InMap()) {
  707.     List<charp> taxl;
  708.     // MarkM made max tax rate limited by luxuries rate (and vice-versa):
  709.     for (int i = 10-luxuries/10; i >= 0; --i) {
  710.       char *str = new char[20];
  711.       sprintf(str, "Tax %d%%", i*10);
  712.       taxl.Insert(str);
  713.     }
  714.     state = IN_SELECT;
  715.     selecting = TAX_RATE;
  716.     screen->CreateChoiceFrame("Set Tax Rate ...", taxl);
  717.     while (taxl) delete taxl.RemoveHead();
  718.   }
  719.   // MarkM added luxuries rate:
  720.   else if (ch == 'l' && display->InMap()) {
  721.     List<charp> luxl;
  722.     for (int i = 10-tax/10; i >= 0; --i) {
  723.       char *str = new char[20];
  724.       sprintf(str, "Luxuries %d%%", i*10);
  725.       luxl.Insert(str);
  726.     }
  727.     state = IN_SELECT;
  728.     selecting = LUXURY_RATE;
  729.     screen->CreateChoiceFrame("Set Luxuries Rate ...", luxl);
  730.     while (luxl) delete luxl.RemoveHead();
  731.   }
  732.   else if (ch == 'r') {
  733.     world->DrawMainMap();
  734.     screen->Refresh();
  735.   }
  736.   // MarkM added revolution (changing govt type to ANARCHY):
  737.   else if (ch == 'g' && display->InMap() && govt != ANARCHY) {
  738.     if (HasWonder("Pyramids")) ChooseGovernment();
  739.     else {
  740.       List<charp> revl;
  741.       char *str1 = new char[30];
  742.       sprintf(str1,"No revolution thank you.");
  743.       revl.Insert(str1);
  744.       char *str2 = new char[30];
  745.       sprintf(str2,"Yes, time for a revolution!");
  746.       revl.Insert(str2);
  747.       state = IN_SELECT;
  748.       selecting = REVOLUTION;
  749.       screen->CreateChoiceFrame("Revoltion?", revl);
  750.       while (revl) delete revl.RemoveHead();
  751.     }
  752.   }
  753.   else if (MovementKey(ch) && display->InMap()) {
  754.     int xinc = MoveXDir(ch), yinc = MoveYDir(ch);
  755.     if (yinc < 0) display->ScrollUp();
  756.     if (yinc > 0) display->ScrollDown();
  757.     if (xinc < 0) display->ScrollLeft();
  758.     if (xinc > 0) display->ScrollRight();
  759.     screen->Refresh();
  760.   }
  761.   else if (ch == 'm' && display->InCity()) {
  762.     City *city;
  763.     if ((city = FindCityWithMsg()) != NULL) {
  764.       display->ShowCityInfo(city);
  765.       screen->MessageBox(city->messages.RemoveHead());
  766.     }
  767.     else
  768.       display->ShowMap();
  769.   }
  770.   else if (ch == 'S') {
  771.     if (playerId == 0)
  772.       initiatedSave = 1;
  773.     else if (initiatedSave) {
  774.       CreateSaveFile();
  775.       exit(0);
  776.     }
  777.   }
  778. }
  779.  
  780. // message in city turn
  781. void Player::CityTurnMesg(MsgQ *q)
  782. {
  783.   char *mesg;
  784.   *q >> mesg;
  785.   if (strcmp(mesg, "myturn") == 0) { // acknowledge a moveturn
  786.     int player;
  787.     *q >> player;
  788.     if (player != currTurn) {
  789.       Debug('n',"Myturn from %d; currTurn is %d!\n",player, currTurn);
  790.       NetFail("CityTurn");
  791.     }
  792.     MsgQ *q1 = new MsgQ;
  793.     *q1 << "yourturn_ack";
  794.     SendQ(q1);
  795.     delete q;
  796.   }
  797.   else if (strcmp(mesg, "turn_done") == 0) {
  798.     int player;
  799.     *q >> player;
  800.     if (player != currTurn) {
  801.       Debug('n',"Turndone from %d; currTurn is %d!\n",player, currTurn);
  802.       NetFail("CityTurn");
  803.     }
  804.     char *str;
  805.     *q >> str;
  806.     delete str;
  807.     players[currTurn]->unDispQ = q;
  808.     Debug('p', "got turn done from %d\n", currTurn);
  809.     if ((numPlayers > 2) && ((currTurn+1) % numPlayers) == id) {
  810.       accepts_left = numPlayers-2;
  811.       screen->DisplayMessage("Waiting for turn...", 0);
  812.     }
  813.     else {
  814.       players[currTurn]->doneMoving = 1;
  815.       screen->DisplayMessage("Done: press Accept", 0);
  816.     }
  817.   }
  818.   else if (accepts_left > 0 && strcmp(mesg,"got_moves") ==0) {
  819.     if (--accepts_left <= 0) {
  820.       players[currTurn]->doneMoving = 1;
  821.       screen->DisplayMessage("Done: press Accept", 0);
  822.     }
  823.   }
  824.   else if (playerId != 0 && strcmp(mesg, "save_game") == 0) {
  825.     screen->DisplayMessage("Got Save Request", 0);
  826.     initiatedSave = 1;
  827.   }
  828.   else
  829.     delete q;
  830.   delete mesg;
  831. }
  832.  
  833. // update cities
  834. // send the list of places where they are working to everyone too
  835. void Player::UpdateCities()
  836. {
  837.   Lister<ulong> cityl = citys;
  838.   while (cityl) {
  839.     City *city = trans->TransCity(cityl.Elem());
  840.     if (city->ownerId != id || !city->Update()) { // lost this city
  841.       while (city->units) {
  842.     Unit *unit = trans->TransUnit(city->units.RemoveHead());
  843.     *moveQ << PieceMove(unit->id, PIECE_DIE, 0, 0);
  844.     delete unit;
  845.       }
  846.       if (city->ownerId == id) { // city died
  847.     *moveQ << PieceMove(city->id, CITY_DIE, 0, 0);
  848.     cityl.Delete(); // MUST do this first
  849.     delete city;
  850.       }
  851.       else
  852.     cityl.Delete();
  853.     }
  854.     else {
  855.       *moveQ << PieceMove(city->id, CITY_WORK_MAP, 0, 0);
  856.       int len;
  857.       char *cmap = city->MakeWorkMap(len);
  858.       *moveQ << Msg(cmap, len);
  859.       cityl.Next();
  860.     }
  861.   }
  862.   if (scienceAcc >= needScience && researching != NULL) {
  863.     scienceAcc -= needScience;
  864.     if (scienceAcc > needScience) scienceAcc = needScience;
  865.     Discover(id, researching, discovered, canDiscover, canBuild, canGovern);
  866.     *moveQ << PieceMove(id, DISCOVERY, 0, 0);
  867.     *moveQ << researching;
  868.     researching = NULL;
  869.   }
  870.   // MarkM added 40% chance if ANARCHY of getting to select govt type:
  871.   if (govt == ANARCHY && random() %9 <= 3) ChooseGovernment();
  872. }
  873.  
  874. void Player::WonderEffect(City *city)
  875. {
  876.   for (Lister<charp> l = wonders; l; l.Next()) {
  877.     BuildObject *obj = buildObjects.Find(StrKey(l.Elem()));
  878.     if (WonderObsolete(obj, id)) {
  879.       switch (obj->type) {
  880.       case COLOSSUS:
  881.     tradeBonus = 0;
  882.     break;
  883.       case MICHELANGELO:
  884.     cathedralEffect = 4;
  885.     break;
  886.       case ORACLE:
  887.     templeEffect = 2;
  888.         break;
  889.       case LIGHTHOUSE:
  890.         if (!HasWonder("Magellan's Expedition")) seamoveBonus = 0;
  891.         break;
  892.       case MAGELLAN:
  893.         if (!HasWonder("Light House")) seamoveBonus = 0;
  894.         break;
  895.       }
  896.       continue;
  897.     }
  898.     switch (obj->type) {
  899.     case COPERNICUS:
  900.       if (city->HasBuilding(obj->name))
  901.     city->science *= 2;
  902.       break;
  903.     case CUREFORCANCER:
  904.       ++city->happy;
  905.       break;
  906.     case HANGINGGARDENS:
  907.       ++city->happy;
  908.       break;
  909.     case HOOVERDAM:
  910.       if (city->HasBuilding("Factory"))
  911.     city->prod = int(city->prod*1.5);
  912.       break;
  913.     case ISAACNEWTON:
  914.       if (city->HasBuilding("University"))
  915.     city->science = int(city->science*1.5);
  916.       break;
  917.     case JSBACH:
  918.       city->goondas -= 2;
  919.       if (city->goondas < 0) city->goondas = 0;
  920.       break;
  921.     case MICHELANGELO:
  922.       cathedralEffect = 6;
  923.     case ORACLE:
  924.       templeEffect = 4;
  925.       break;
  926.     case SHAKESPEARE:
  927.       if (city->HasBuilding(obj->name))
  928.     city->goondas = 0;
  929.       break;
  930.     case LIGHTHOUSE:
  931.     case MAGELLAN:
  932.       seamoveBonus = 1;
  933.     }
  934.   }
  935. }
  936.  
  937. static char *LookupScience(char *str)
  938. {
  939.   Debug('p', "Looking up science %s\n", str);
  940.   Science *sc = sciences.Find(StrKey(str));
  941.   delete str;
  942.   if (sc == NULL)
  943.     return NULL;
  944.   return sc->name;
  945. }
  946.  
  947. void Player::Save()
  948. {
  949.   Debug('s', "Saving player %d\n", id);
  950.   WriteUShort(govt);
  951.   WriteUShort(tax);
  952.   // MarkM added luxuries rate:
  953.   WriteUShort(luxuries);
  954.   WriteUShort(money);
  955.  
  956.   WriteUShort(scienceAcc);
  957.   WriteUShort(needScience);
  958.   WriteString(researching == NULL ? "X" : researching);
  959.  
  960.   WriteUChar(templeEffect);
  961.   WriteUChar(cathedralEffect);
  962.   WriteUChar(seamoveBonus);
  963.   WriteUChar(tradeBonus);
  964.  
  965.   WriteUShort(discovered.Count());
  966.   Lister<charp> l;
  967.   for (l = discovered; l; l.Next())
  968.     WriteString(l.Elem());
  969.  
  970.   WriteUShort(canDiscover.Count());
  971.   for (l = canDiscover; l; l.Next())
  972.     WriteString(l.Elem());
  973.  
  974.   WriteUShort(canBuild.Count());
  975.   for (l = canBuild; l; l.Next())
  976.     WriteString(l.Elem());
  977.  
  978.   // MarkM added canGovern list of available government types:
  979.   WriteUShort(canGovern.Count());
  980.   for (l = canGovern; l; l.Next())
  981.     WriteString(l.Elem());
  982.  
  983.   WriteUShort(wonders.Count());
  984.   for (l = wonders; l; l.Next())
  985.     WriteString(l.Elem());
  986.  
  987.   WriteUShort(citys.Count());
  988.   Lister<ulong> l1;
  989.   for (l1 = citys; l1; l1.Next())
  990.     trans->TransCity(l1.Elem())->Save();
  991.  
  992.   WriteUShort(units.Count());
  993.   for (l1 = units; l1; l1.Next())
  994.     trans->TransUnit(l1.Elem())->Save();
  995. }
  996.  
  997. void Player::Restore()
  998. {
  999.   Debug('s', "Restoring player %d\n", id);
  1000.   govt = ReadUShort();
  1001.   tax = ReadUShort();
  1002.   // MarkM added luxuries rate:
  1003.   luxuries = ReadUShort();
  1004.   money = ReadUShort();
  1005.  
  1006.   scienceAcc = ReadUShort();
  1007.   needScience = ReadUShort();
  1008.   researching = LookupScience(ReadString());
  1009.   Debug('s', "Restored upto researching %s\n", researching);
  1010.  
  1011.   templeEffect = ReadUChar();
  1012.   cathedralEffect = ReadUChar();
  1013.   seamoveBonus = ReadUChar();
  1014.   tradeBonus = ReadUChar();
  1015.   int n = ReadUShort();
  1016.   Debug('s', "Restoring %d discovered\n", n);
  1017.   for (; n > 0; --n) {
  1018.     char *name = LookupScience(ReadString());
  1019.     discovered.Insert(name);
  1020.     Science *sc = sciences.Find(StrKey(name));
  1021.     sc->discovered |= 1 << id;
  1022.     if (sc->wonderObsolete != NULL)
  1023.       buildObjects.Find(StrKey(sc->wonderObsolete))->isObsolete = 1;
  1024.   }
  1025.  
  1026.   n = ReadUShort();
  1027.   Debug('s', "Restoring %d can discover\n", n);
  1028.   for (; n > 0; --n)
  1029.     canDiscover.Insert(LookupScience(ReadString()));
  1030.  
  1031.   n = ReadUShort();
  1032.   Debug('s', "Restoring %d can build\n", n);
  1033.   for (; n > 0; --n) {
  1034.     char *str = ReadString();
  1035.     BuildObject *obj = buildObjects.Find(StrKey(str));
  1036.     delete str;
  1037.     canBuild.Insert(obj->name);
  1038.   }
  1039.  
  1040.   n = ReadUShort();
  1041.   Debug('s', "Restoring %d can govern\n", n);
  1042.   for (; n > 0; --n)
  1043.     canGovern.Insert(LookupScience(ReadString()));
  1044.  
  1045.   n = ReadUShort();
  1046.   Debug('s', "Restoring %d wonders\n", n);
  1047.   for (; n > 0; --n) {
  1048.     char *str = ReadString();
  1049.     BuildObject *obj = buildObjects.Find(StrKey(str));
  1050.     delete str;
  1051.     wonders.Insert(obj->name);
  1052.     obj->built = 1;
  1053.   }
  1054.  
  1055.   n = ReadUShort();
  1056.   Debug('s', "Restoring %d cities\n", n);
  1057.   for (; n > 0; --n)
  1058.     City *city = new City; // default constructor reads from save file
  1059.  
  1060.   n = ReadUShort();
  1061.   Debug('s', "Restoring %d units\n", n);
  1062.   for (; n > 0; --n)
  1063.     Unit *unit = new Unit; // default constructor reads from save file
  1064.  
  1065.   // compute economies
  1066.   if (playerId == id)
  1067.     for (Lister<ulong> l = citys; l; l.Next())
  1068.       trans->TransCity(l.Elem())->ComputeEcon();
  1069. }
  1070.